package com.sdy.usercenter.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.sdy.common.utils.DesensitizeUtil;
import com.sdy.common.utils.MapUtil;
import com.sdy.common.utils.StringUtil;
import com.sdy.mvc.utils.JsonUtil;
import com.sdy.usercenter.biz.model.SysDept;
import com.sdy.usercenter.biz.mapper.SysDeptMapper;
import com.sdy.usercenter.biz.model.SysUser;
import com.sdy.usercenter.biz.model.SysUserDept;
import com.sdy.usercenter.biz.model.vo.DeptVO;
import com.sdy.usercenter.biz.model.vo.LayTreeItem;
import com.sdy.usercenter.biz.model.vo.UserDeptInfoVo;
import com.sdy.usercenter.biz.service.SysDeptService;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.sdy.usercenter.biz.service.SysUserDeptService;
import com.sdy.usercenter.biz.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 组织机构信息表 服务实现类
 * </p>
 *
 * @author zzq
 * @since 2019-06-14
 */
@Slf4j
@Service
public class SysDeptServiceImpl extends BaseServiceImpl<SysDept> implements SysDeptService {
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private SysUserDeptService sysUserDeptService;
    @Autowired
    private SysUserService sysUserService;

    @Override
    public LayTreeItem getDeptTree() {
        List<SysDept> deptList = list();
        List<LayTreeItem> authList = deptList.stream()
                .map(item -> new LayTreeItem()
                        .setId(item.getId())
                        .setSpread(true)
                        .setTitle(item.getAbbreviation())
                        .setParentId(item.getParentId())
                        .setName(item.getAbbreviation())
                        .setOpen(false))
                .collect(Collectors.toList());
        List<LayTreeItem> rootDept = new ArrayList<>();
        Map<Integer, LayTreeItem> m = new HashMap<>();
        for (LayTreeItem item : authList) {
            m.put(item.getId(), item);
        }
        for (LayTreeItem item : authList) {
            if (item.getParentId() == null || item.getParentId() <= 0) {
                rootDept.add(item);
            } else {
                LayTreeItem parent = m.get(item.getParentId());
                if (parent == null) {
                    rootDept.add(item);
                    break;
                }
                List<LayTreeItem> children = parent.getChildren();
                if (children == null) {
                    children = new ArrayList<>();
                }
                children.add(item);
                parent.setChildren(children);
            }
        }
        return new LayTreeItem().setChildren(rootDept);
    }

    @Override
    public IPage<UserDeptInfoVo> managerPageData(IPage<SysUserDept> page, Map<String, Object> query, Integer deptId) {
        IPage<SysUserDept> userDeptPage = sysUserDeptService.page(page, new QueryWrapper<SysUserDept>().eq("dept_id", deptId).eq("admin", 1));
        if (userDeptPage.getRecords().isEmpty()) {
            return new Page<UserDeptInfoVo>(1, 1, 0).setRecords(new ArrayList<>());
        }
        // 所有用户
        List<Integer> userIdList = userDeptPage.getRecords().stream().map(SysUserDept::getUserId).collect(Collectors.toList());
        List<SysUser> userList = new ArrayList<>(sysUserService.listByIds(userIdList));
        Map<Integer, SysUser> userMap = new HashMap<>();
        userList.forEach(item -> userMap.put(item.getId(), item));

        // 所有组织
        List<SysUserDept> allUserDeptList = sysUserDeptService.list(new QueryWrapper<SysUserDept>().eq("dept_id", deptId));
        List<SysDept> allDeptList = new ArrayList<>(listByIds(allUserDeptList.stream().map(SysUserDept::getDeptId).collect(Collectors.toList())));
        allDeptList.forEach(item -> item.setCode(null).setUniscid(null));
        
        // 用户所属组织
        List<SysUserDept> ownDeptIdList = allUserDeptList.stream().filter(item -> item.getAdmin().equals(2)).collect(Collectors.toList());
        
        // 用户管理的所有组织
        List<SysUserDept> manageDeptIdList = allUserDeptList.stream().filter(item -> item.getAdmin().equals(1)).collect(Collectors.toList());

        // 组装数据
        List<UserDeptInfoVo> resultList = new ArrayList<>();
        for (SysUserDept userDept : userDeptPage.getRecords()) {
            UserDeptInfoVo vo = new UserDeptInfoVo();
            SysUser user = userMap.get(userDept.getUserId());
            vo.setId(user.getId())
                    .setIdCard(DesensitizeUtil.hideIdCardNo(user.getIdCard()))
                    .setName(user.getName())
                    .setPhone(user.getPhone())
                    .setState(user.getState())
                    .setType(user.getType())
                    .setUserNo(user.getUserNo())
                    .setOwnDeptList(allDeptList.stream().filter(dept -> {
                        for (SysUserDept sysUserDept : ownDeptIdList) {
                            if (sysUserDept.getUserId().equals(user.getId()) && sysUserDept.getDeptId().equals(dept.getId())) {
                                return true;
                            }
                        }
                        return false;
                    }).collect(Collectors.toList()))
                    .setManageDeptList(allDeptList.stream().filter(dept -> {
                        for (SysUserDept sysUserDept : manageDeptIdList) {
                            if (sysUserDept.getUserId().equals(user.getId()) && sysUserDept.getDeptId().equals(dept.getId())) {
                                return true;
                            }
                        }
                        return false;
                    }).collect(Collectors.toList()));
            resultList.add(vo);
        }
        return new Page<UserDeptInfoVo>(userDeptPage.getCurrent(), userDeptPage.getSize(), userDeptPage.getTotal()).setRecords(resultList);
    }

    @Override
    public IPage<UserDeptInfoVo> userPageData(IPage<SysUserDept> page, Map<String, Object> query, Integer deptId) {
        IPage<SysUserDept> userDeptPage = sysUserDeptService.page(page, new QueryWrapper<SysUserDept>().eq("dept_id", deptId).eq("admin", 2));
        if (userDeptPage.getRecords().isEmpty()) {
            return new Page<UserDeptInfoVo>(1, 1, 0).setRecords(new ArrayList<>());
        }
        // 所有用户
        List<Integer> userIdList = userDeptPage.getRecords().stream().map(SysUserDept::getUserId).collect(Collectors.toList());
        List<SysUser> userList = new ArrayList<>(sysUserService.listByIds(userIdList));
        Map<Integer, SysUser> userMap = new HashMap<>();
        userList.forEach(item -> userMap.put(item.getId(), item));

        // 所有组织
        List<SysUserDept> allUserDeptList = sysUserDeptService.list(new QueryWrapper<SysUserDept>().eq("dept_id", deptId));
        List<SysDept> allDeptList = new ArrayList<>(listByIds(allUserDeptList.stream().map(SysUserDept::getDeptId).collect(Collectors.toList())));
        allDeptList.forEach(item -> item.setCode(null).setUniscid(null));

        // 用户所属组织
        List<SysUserDept> ownDeptIdList = allUserDeptList.stream().filter(item -> item.getAdmin().equals(2)).collect(Collectors.toList());

        // 组装数据
        List<UserDeptInfoVo> resultList = new ArrayList<>();
        for (SysUserDept userDept : userDeptPage.getRecords()) {
            SysUser user = userMap.get(userDept.getUserId());
            if (user != null) {
                UserDeptInfoVo vo = new UserDeptInfoVo();
                vo.setId(user.getId())
                        .setIdCard(DesensitizeUtil.hideIdCardNo(user.getIdCard()))
                        .setName(user.getName())
                        .setPhone(user.getPhone())
                        .setState(user.getState())
                        .setType(user.getType())
                        .setUserNo(user.getUserNo())
                        .setOwnDeptList(allDeptList.stream().filter(dept -> {
                            for (SysUserDept sysUserDept : ownDeptIdList) {
                                if (sysUserDept.getUserId().equals(user.getId()) && sysUserDept.getDeptId().equals(dept.getId())) {
                                    return true;
                                }
                            }
                            return false;
                        }).collect(Collectors.toList()));
                resultList.add(vo);
            }
        }
        return new Page<UserDeptInfoVo>(userDeptPage.getCurrent(), userDeptPage.getSize(), userDeptPage.getTotal()).setRecords(resultList);
    }

    @Override
    public Integer addManagerBatch(List<Integer> userIdList, Integer deptId) {
        if (userIdList.isEmpty() || deptId == null) {
            return 0;
        }
        List<SysUserDept> userDeptList = sysUserDeptService.list(new QueryWrapper<SysUserDept>()
                .eq("dept_id", deptId).in("user_id", userIdList).eq("admin", 1));
        userIdList.removeAll(userDeptList.stream().map(SysUserDept::getUserId).collect(Collectors.toList()));
        if (userIdList.isEmpty()) {
            return 0;
        }
        userIdList.forEach(item -> sysUserDeptService.save(new SysUserDept()
                .setDeptId(deptId)
                .setUserId(item)
                .setAdmin(1)
                .setCreateTime(new Date()))
        );
        return userIdList.size();
    }

    @Override
    public Integer delManagerBatch(List<Integer> userIdList, Integer deptId) {
        if (userIdList.isEmpty() || deptId == null) {
            return 0;
        }
        sysUserDeptService.remove(new QueryWrapper<SysUserDept>()
                .eq("dept_id", deptId).in("user_id", userIdList).eq("admin", 1));
        return userIdList.size();
    }
    
    private void initParentData(Integer parentId) {
        SysDept parentDept = getOne(new LambdaQueryWrapper<SysDept>().eq(SysDept::getId, parentId));
        if (parentDept != null) {
            lambdaUpdate().set(SysDept::getParentId, parentId)
                    .likeRight(SysDept::getCode, parentDept.getCode())
                    .isNull(SysDept::getParentId)
                    .last(" and length(code) = " + (parentDept.getCode().length() + 3)).update();
        }
    }

    @Override
    public List<DeptVO> listSubDept(Integer parentId) {
        parentId = parentId == null ? 0 : parentId;
//        initParentData(parentId);
        SysDept parentDept = getOne(new LambdaQueryWrapper<SysDept>().eq(SysDept::getId, parentId));
        List<SysDept> deptList;
        int parentCodeLen;
        if (parentId == 0) {
            parentCodeLen = 0;
            deptList = lambdaQuery()
                    .eq(SysDept::getParentId, 0)
                    .select(SysDept::getName, SysDept::getState, SysDept::getId, SysDept::getAbbreviation, SysDept::getCode, SysDept::getLevel)
                    .list();
        } else {
            parentCodeLen = parentDept.getCode().length();
            deptList = lambdaQuery()
                    .likeRight(SysDept::getCode, parentDept.getCode())
                    .eq(SysDept::getLevel, parentDept.getLevel() + 1)
                    .last(" and length(code) = " + (parentCodeLen + 3))
                    .select(SysDept::getName, SysDept::getState, SysDept::getId, SysDept::getAbbreviation, SysDept::getCode, SysDept::getLevel)
                    .list();
        }
        List<DeptVO> voList = new ArrayList<>();
        Map<String, List<SysDept>> childrenMap = Collections.emptyMap();
        if (!deptList.isEmpty()) {
            List<Integer> idList = deptList.stream().map(SysDept::getId).collect(Collectors.toList());
            List<SysDept> childrenList = lambdaQuery()
                    .likeRight(parentId != 0, SysDept::getCode, parentId == 0 ? "" : parentDept.getCode())
                    .eq(SysDept::getLevel, deptList.get(0).getLevel() + 1)
                    .last(" and length(code) = " + (parentCodeLen + 6))
                    .select(SysDept::getId, SysDept::getState, SysDept::getCode)
                    .list();
            childrenMap = MapUtil.collectionToMapList(childrenList, item -> item.getCode().substring(0, item.getCode().length() - 3));
        }
        for (SysDept dept : deptList) {
            List<SysDept> children = childrenMap.get(dept.getCode());
            DeptVO vo = new DeptVO()
                    .setId(dept.getId())
                    .setCode(dept.getCode())
                    .setName(dept.getName())
                    .setParentId(dept.getParentId())
                    .setState(dept.getState())
                    .setAbbreviation(dept.getAbbreviation());
            if (children != null && !children.isEmpty()) {
                vo.setAbbreviation(vo.getAbbreviation());
                vo.setSubCount(children.size());
                vo.setExpand(true);
            } else {
                vo.setSubCount(0);
                vo.setExpand(false);
            }
            vo.setParentId(parentId);
//            vo.setExpand(true);
            voList.add(vo);
        }
        return voList;
    }

    @Override
    public SysDept getByCode(String code) {
        return getOne(new LambdaQueryWrapper<SysDept>().eq(SysDept::getCode, code));
    }

    @Override
    public List<DeptVO> listDept(String keyword) {
        if (StringUtil.isBlank(keyword)) {
            return Collections.emptyList();
        }
        List<DeptVO> voList = new ArrayList<>();
        List<SysDept> deptList = lambdaQuery().like(SysDept::getAbbreviation, keyword.trim()).list();
        if (deptList.size() > 3000) {
            return Collections.emptyList();
        }
        Set<String> parentCodeSet = deptList.stream()
                .map(SysDept::getCode)
                .filter(code -> code.length() > 3)
                .map(code -> code.substring(0, code.length() - 3)).collect(Collectors.toSet());
        Set<String> pSet = parentCodeSet;
        while (pSet.stream().anyMatch(code -> code.length() > 3)) {
            pSet = pSet.stream()
                    .filter(code -> code.length() > 3)
                    .map(code -> code.substring(0, code.length() - 3))
                    .collect(Collectors.toSet());
            parentCodeSet.addAll(pSet);
        }
        List<SysDept> parentDeptList = Collections.emptyList();
        if (!parentCodeSet.isEmpty()) {
            parentDeptList = lambdaQuery().in(SysDept::getCode, parentCodeSet).list();
        }
        List<Integer> deptIdList = deptList.stream().map(SysDept::getId).collect(Collectors.toList());
        parentDeptList.forEach(p -> {
            if (!deptIdList.contains(p.getId())) {
                deptList.add(p);
            }
        });
        Map<String, SysDept> parentDeptMap = MapUtil.collectionToMap(deptList, SysDept::getCode);
        for (SysDept dept : deptList) {
            DeptVO vo = new DeptVO()
                    .setId(dept.getId())
                    .setCode(dept.getCode())
                    .setName(dept.getName())
                    .setState(dept.getState())
                    .setParentId(dept.getParentId())
                    .setAbbreviation(dept.getAbbreviation());
            vo.setAbbreviation(vo.getAbbreviation());
            vo.setExpand(true);
            String parentCode = dept.getCode().length() > 3 ? dept.getCode().substring(0, dept.getCode().length() - 3) : "";
            SysDept parentDept = parentDeptMap.get(parentCode);
            vo.setParentId(parentDept == null ? null : parentDept.getId());
            voList.add(vo);
        }
        return voList;
    }


    @Override
    public List<SysDept> getDeptAccessorList(Integer deptId) {
        List<SysDept> r = new ArrayList<>();
        SysDept dept = getById(deptId);
        if (dept == null) {
            return r;
        }
        r.add(dept);
        String code = dept.getCode();
        while (code.length() > 3) {
            code = code.substring(0, code.length() - 3);
            dept = lambdaQuery().eq(SysDept::getCode, code).one();
            if (dept != null) {
                r.add(dept);
            } else {
                break;
            }
        }
        return r;
    }

    @Override
    public synchronized void updateDept(SysDept sysDept) {
        SysDept origin = getById(sysDept.getId());
        updateById(sysDept);
        if (!StringUtil.equals(origin.getSuffix(), sysDept.getSuffix())) {
            List<Integer> userIdList = sysUserDeptService.lambdaQuery()
                    .select(SysUserDept::getUserId)
                    .eq(SysUserDept::getDeptId, origin.getId())
                    .list().stream().map(SysUserDept::getUserId).collect(Collectors.toList());
            if (!userIdList.isEmpty()) {
                List<SysUser> userList = sysUserService.list();
                userList.forEach(user -> {
                    SysUserDept rootUserDept = sysUserDeptService.lambdaQuery()
                            .eq(SysUserDept::getUserId, user.getId())
                            .eq(SysUserDept::getAdmin, 2)
                            .orderByAsc(SysUserDept::getPrimaryDept)
                            .last("limit 1")
                            .one();
                    if (rootUserDept != null) {
                        String suffix = sysUserService.getUserDeptSuffix(null, rootUserDept.getDeptId());
                        sysUserService.lambdaUpdate()
                                .eq(SysUser::getId, user.getId())
                                .setSql(String.format("login_name=concat(simple_login_name,'%s')", suffix))
                                .update();
                    }
                });
            }
        }
    }
}
